package com.want.controller;

import com.want.entity.BlogContext;
import com.want.entity.BlogMetaDataNameAndCount;
import com.want.entity.BlogType;
import com.want.entity.Tag;
import com.want.model.dto.Result;
import com.want.model.dto.ResultUtil;
import com.want.repository.BlogContextRepository;
import com.want.repository.BlogRepository;
import com.want.repository.BlogTagRepository;
import com.want.repository.BlogTypeRepository;
import com.want.req.base.PageReqDto;
import com.want.req.blog.dto.CreateBlogDto;
import com.want.req.blog.dto.ListBlogReqDto;
import com.want.req.blog.dto.PoolBlogDto;
import com.want.req.blog.dto.UpdateBlogDto;
import com.want.resp.base.PageResp;
import com.want.resp.blog.dto.*;
import com.want.service.BlogService;
import com.want.util.MyBeanUtil;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @author WangZhiJian
 * @since 2021/11/30 0030
 */
@RestController
@RequestMapping("blog")
public class BlogController {

    @Resource
    private BlogRepository blogRepository;
    @Resource
    private BlogService blogService;
    @Resource
    private BlogContextRepository blogContextRepository;
    @Resource
    private BlogTypeRepository blogTypeRepository;
    @Resource
    private BlogTagRepository blogTagRepository;


    @GetMapping("{id}")
    public Mono<Result<BlogDto>> blog(@PathVariable("id")Integer id){
        return blogService.blog(id);
    }

    @PostMapping("goodBlog")
    public Mono<Result<Integer>> goodBlog(@RequestBody PoolBlogDto poolBlogDto){
        return blogService.goodBlog(poolBlogDto);
    }

    @PostMapping("/delete")
    public Mono<Result<Integer>> delete(@RequestBody @NotEmpty @NotNull List<Integer> idList){
        return blogService.deleteBlog(idList);
    }

    @PostMapping("createBlog")
    public Mono<Result<Integer>> createBlog(@RequestBody CreateBlogDto createBlogDto){
        return blogService.saveBlog(createBlogDto);
    }

    @PostMapping("updateBlog")
    public Mono<Result<Integer>> updateBlog(@RequestBody UpdateBlogDto updateBlogDto){
        return blogService.updateBlog(updateBlogDto);
    }

    @PostMapping(value = "listBlog")
    public Mono<Result<PageResp<BlogDto>>> listBlog(@RequestBody PageReqDto<ListBlogReqDto> pageReqDto){
        return blogService.listAllBlog(pageReqDto);
    }
    @GetMapping(value = "listAllBlogTag")
    public Mono<Result<PageResp<BlogTagDto>>> listAllBlogTag(){
        return blogTagRepository.findAll()
                .map(blogTag -> MyBeanUtil.copyProperties(blogTag,BlogTagDto.class))
                .collectList()
                .map(list -> PageResp.<BlogTagDto>builder().pages(1L).result(list).build())
                .map(ResultUtil::ofSuccess);
    }
    @GetMapping(value = "listAllBlogType")
    public Mono<Result<PageResp<BlogTypeDto>>> listAllBlogType(){
        return blogTypeRepository.findAll()
                .map(blogType -> MyBeanUtil.copyProperties(blogType,BlogTypeDto.class))
                .collectList()
                .map(list -> PageResp.<BlogTypeDto>builder().pages(1L).result(list).build())
                .map(ResultUtil::ofSuccess);
    }
    private DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    @ApiOperation(value = "获取一年内的文章贡献数和日期", notes = "获取一年内的文章贡献数和日期")
    @GetMapping("/getBlogContributeCountAndDates")
    public Mono<BlogMetaDataNameAndCountRespDto> getBlogContributeCountAndDates() {
        LocalDate curDate = LocalDate.now();
        return blogRepository.getBlogContributeCountAndDates(curDate.minusDays(365),curDate, BlogMetaDataNameAndCount.class)
                .collectList()
                .map(list -> {
                    BlogMetaDataNameAndCountRespDto dto = new BlogMetaDataNameAndCountRespDto();
                    Map<String, Integer> existMap = list.stream().collect(Collectors.toMap(BlogMetaDataNameAndCount::getName, BlogMetaDataNameAndCount::getCount, (v1, v2) -> v1));
                    List<Object[]> res = IntStream.range(0, 365)
                            .mapToObj(curDate::minusDays)
                            .map(dateTimeFormatter::format)
                            .map(key ->
                                    new BlogMetaDataNameAndCountDto(key, existMap.getOrDefault(key, 0))
                            ).map(BlogMetaDataNameAndCountDto::toObject).collect(Collectors.toList());
                    dto.setBlogMetaDataNameAndCountDtos(res);
                    dto.setStart(curDate.minusDays(365));
                    dto.setEnd(curDate);
                    return dto;
                });
    }

    @ApiOperation(value = "获取每个分类下文章数目", notes = "获取每个分类下文章数目")
    @GetMapping(value = "/getBlogCountByBlogSort")
    public Mono<List<SimpleBlogMetaDataNameAndCountDto>> getBlogCountByBlogSort() {
        return blogRepository.getBlogCountByBlogType(BlogMetaDataNameAndCount.class)
                .map(res -> MyBeanUtil.copyProperties(res,BlogMetaDataNameAndCountDto.class))
                .collectList()
                .map(list -> list.stream()
                        .map(item -> SimpleBlogMetaDataNameAndCountDto.builder().name(item.getName()).value(item.getCount()).build())
                        .collect(Collectors.toList())
                );
    }
    @GetMapping("blog/getContent/{id}")
    public Mono<Result<String>> getContent(@PathVariable("id") Integer id){
        return blogContextRepository.findByBlogId(id)
                .map(BlogContext::getBlogContent)
                .map(ResultUtil::ofSuccess)
                .switchIfEmpty(Mono.defer(() -> Mono.just(ResultUtil.ofFail("NOT FOUNT",String.class))));
    }

    @PostMapping("blogType/add")
    public Mono<Result<BlogTypeDto>> addBlogType(@RequestBody BlogTypeDto blogTypeDto){
        return blogTypeRepository.save(MyBeanUtil.copyProperties(blogTypeDto, BlogType.class))
                .map(tag -> MyBeanUtil.copyProperties(tag,BlogTypeDto.class))
                .map(ResultUtil::ofSuccess)
                .switchIfEmpty(Mono.defer(() -> Mono.just(ResultUtil.ofFail("添加失败！",BlogTypeDto.class))));
    }
    @PostMapping("blogType/delete")
    public Mono<Result<List<Integer>>> deleteBlogType(@RequestBody List<Integer> idList){
        return blogTypeRepository.deleteAllById(idList)
                .then(Mono.defer(() -> Mono.just(ResultUtil.ofSuccess(idList))));
    }
    @PostMapping("blogType/update")
    public Mono<Result<BlogTypeDto>> updateBlogType(@RequestBody BlogTypeDto blogTypeDto){
        return blogTypeRepository.save(MyBeanUtil.copyProperties(blogTypeDto, BlogType.class))
                .map(tag -> MyBeanUtil.copyProperties(tag,BlogTypeDto.class))
                .map(ResultUtil::ofSuccess)
                .switchIfEmpty(Mono.defer(() -> Mono.just(ResultUtil.ofFail("修改失败！",BlogTypeDto.class))));
    }

    @PostMapping("blogTag/add")
    public Mono<Result<BlogTagDto>> addBlogTag(@RequestBody BlogTagDto blogTagDto){
        return blogTagRepository.save(MyBeanUtil.copyProperties(blogTagDto, Tag.class))
                .map(tag -> MyBeanUtil.copyProperties(tag,BlogTagDto.class))
                .map(ResultUtil::ofSuccess)
                .switchIfEmpty(Mono.defer(() -> Mono.just(ResultUtil.ofFail("添加失败！",BlogTagDto.class))));
    }
    @PostMapping("blogTag/delete/")
    public Mono<Result<List<Integer>>> deleteBlogTag(@RequestBody List<Integer> idList){
        return blogTagRepository.deleteAllById(idList)
                .then(Mono.defer(() -> Mono.just(ResultUtil.ofSuccess(idList))));
    }
    @PostMapping("blogTag/update")
    public Mono<Result<BlogTagDto>> updateBlogTag(@RequestBody BlogTagDto blogTagDto){
        return blogTagRepository.save(MyBeanUtil.copyProperties(blogTagDto, Tag.class))
                .map(tag -> MyBeanUtil.copyProperties(tag,BlogTagDto.class))
                .map(ResultUtil::ofSuccess)
                .switchIfEmpty(Mono.defer(() -> Mono.just(ResultUtil.ofFail("修改失败！",BlogTagDto.class))));
    }

    @ApiOperation(value = "获取每个标签下文章数目", notes = "获取每个标签下文章数目", response = String.class)
    @GetMapping(value = "/getBlogCountByBlogTag")
    public Mono<List<SimpleBlogMetaDataNameAndCountDto>> getBlogCountByBlogTag() {
        return blogRepository.getBlogCountByBlogTag(BlogMetaDataNameAndCount.class)
                .concatMapIterable(item -> Stream.of(item.getName().split(","))
                            .map(id -> {
                                BlogMetaDataNameAndCountDto blogMetaDataNameAndCount = MyBeanUtil.copyProperties(item, BlogMetaDataNameAndCountDto.class);
                                blogMetaDataNameAndCount.setName(String.valueOf(id));
                                return blogMetaDataNameAndCount;
                            }).collect(Collectors.toList())
                )
                .collectList()
                .map(list -> list.stream()
                        .collect(Collectors.groupingBy(BlogMetaDataNameAndCountDto::getName
                                ,Collectors.collectingAndThen(Collectors.toList(),tempList -> tempList.stream().reduce((v1,v2)->{
                                    v1.setCount(v1.getCount()+v2.getCount());
                                    return v1;
                                }).orElseGet(BlogMetaDataNameAndCountDto::new)))).values())
                .map(list -> list.stream()
                        .map(item -> SimpleBlogMetaDataNameAndCountDto.builder().name(item.getName()).value(item.getCount()).build())
                        .collect(Collectors.toList())
                );

    }
}
